﻿using km_sso_server.Models;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using System.ServiceModel.Channels;
using km_sso_library;
using System.Linq;
using System.ComponentModel;

namespace km_sso_server.Controllers
{
    /// <summary>
    /// 单点登录接口
    /// </summary>
    public class SSOController : ApiController
    {
        //km_sso_db.SSONFineBaseEntities db = new km_sso_db.SSONFineBaseEntities();
        NFineBaseEntities db = new NFineBaseEntities();
        #region CheckOnline API

        /// <summary>
        /// 检查用户在线接口
        /// </summary>
        /// <param name="info"></param>
        /// <returns>消息实体Result</returns>
        [ActionName("CheckOnline")]
        [HttpPost]
        public Result PostCheckOnline(UserInfo info)
        {
            //checkonline必需参数
            //appkey,appsecret,ip,token,userid

            Result result = new Result();
            try
            {
                //1.检测系统授权
                if (CheckAppPermision(info))
                {
                    //2.检测用户权限
                    if (CheckUserPermission(info))
                    {
                        //3.检测在线用户
                        if (CheckUserIsOnline(ref result, info))
                        {

                        }
                    }
                    else
                    {
                        //没有权限
                        result.Code = 4;
                        result.Message = "该用户没有访问此系统的权限";
                    }
                }
                else
                {
                    //系统未授权
                    result.Code = 3;
                    result.Message = "子系统没有开通SSO";
                }
            }
            catch (Exception ex)
            {
                result.Code = 1;
                result.Message = ex.Message;

            }

            return result;
        }

        #endregion

        #region Login API
        /// <summary>
        /// 用户登录接口
        /// </summary>
        /// <param name="userInfo">用户信息实体UserInfo</param>
        /// <returns>消息实体Result</returns>
        [ActionName("Login")]
        [HttpPost]
        public Result PostLogin(UserInfo userInfo)
        {
            Result result = new Result();
            try
            {
                //1.检测系统授权
                if (CheckAppPermision(userInfo))
                {
                    //2.检测用户名和密码
                    var userId = CheckUsername(userInfo);
                    if (!string.IsNullOrWhiteSpace(userId))
                    {
                        userInfo.UserId = userId;
                        //3,检测用户权限
                        if (CheckUserPermission(userInfo))
                        {
                            //4.判断是否是强制登录
                            if (userInfo.ForceLogin == 1)
                            {
                                LoginSuccess(userInfo, ref result);
                            }
                            //不是强制登录
                            else
                            {
                                //5.检测用户是否在线
                                if (CheckUserIsOnline(ref result, userInfo))
                                {
                                    result.Message = "登录成功";
                                }
                                else
                                {
                                    LoginSuccess(userInfo, ref result);
                                }
                            }
                        }
                        else
                        {
                            //没有权限
                            result.Code = 4;
                            result.Message = "该用户没有访问此系统的权限";
                        }
                    }
                    else
                    {
                        //用户名或密码不正确
                        result.Code = 1;
                        result.Message = "用户名或密码不正确";
                    }

                }
                else
                {
                    //系统未授权
                    result.Code = 3;
                    result.Message = "子系统没有开通SSO";
                }

            }
            catch (Exception ex)
            {
                result.Code = 1;
                result.Message = ex.Message;

            }
            return result;
        }
        #endregion

        #region Logout API
        /// <summary>
        /// 用户注销接口
        /// </summary>
        /// <param name="userInfo">用户信息实体UserInfo</param>
        /// <returns>消息实体Result</returns>
        [ActionName("LoginOut")]
        [HttpPost]
        public Result PostLoginOut(UserInfo userInfo)
        {
            //userid,appkey,appsecret必需参数
            //todo 是否要检测token是否有效?

            //确认有效，注销成功
            //检验失败，注销失败,仍然要注销
            Result result = new Result();
            try
            {
                //1.检测系统授权
                if (CheckAppPermision(userInfo))
                {
                    //2.检测用户权限
                    if (CheckUserPermission(userInfo))
                    {
                        //3,注销用户
                        if (!string.IsNullOrWhiteSpace(userInfo.UserId))
                        {
                            if (RemoveFromRedis(userInfo.UserId))
                            {
                                result.Code = 0;
                                result.Message = "注销成功";
                            }
                            else
                            {
                                result.Code = 1;
                                result.Message = "注销失败";
                            }

                        }
                    }
                    else
                    {
                        //没有权限
                        result.Code = 4;
                        result.Message = "该用户没有访问此系统的权限";
                    }
                }
                else
                {
                    //系统未授权
                    result.Code = 3;
                    result.Message = "子系统没有开通SSO";
                }
            }
            catch (Exception ex)
            {
                result.Code = 1;
                result.Message = ex.Message;

            }

            return result;

        }
        #endregion

        #region 辅助方法

        #region 保存到Redis
        /// <summary>
        /// 保存到Redis
        /// </summary>
        /// <param name="userID"></param>
        /// <param name="loginInfo"></param>
        /// <returns></returns>
        private bool SaveToRedis(string userID, LoginInfo loginInfo)
        {
            bool result = false;
            var exists = RedisCache.Exists(userID);
            //如果Redis中存在此用户
            if (exists)
            {
                //todo 处理已登录的处理逻辑
                RedisCache.AddObject<LoginInfo>(userID, loginInfo, 20);
            }
            //不存在用户
            else
            {
                RedisCache.AddObject<LoginInfo>(userID, loginInfo, 20);
                result = true;
            }

            return result;
        }

        #endregion 保存到Redis 

        #region 删除Redis的Key
        /// <summary>
        /// 删除Redis的Key
        /// </summary>
        /// <param name="userID"></param>
        /// <returns></returns>
        private bool RemoveFromRedis(string userID)
        {
            bool result = false;
            var exists = RedisCache.Exists(userID);
            //如果Redis中存在此用户
            if (exists)
            {
                //todo 处理已登录的处理逻辑
                RedisCache.Remove(userID);
                result = true;
            }
            //不存在用户
            else
            {
                //已经注销了，直接返回注销成功
                result = true;
            }
            return result;
        }

        #endregion 删除Redis的Key

        #region 从Redis查询Key
        private T GetFromRedis<T>(string userID) where T : class, new()
        {
            var loginInfo = RedisCache.Get<T>(userID);
            return loginInfo;
        }
        #endregion 从Redis查询Key

        #region 获取客户端IP
        /// <summary>
        /// 获取客户端IP
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private string ClientIp(HttpRequestMessage request = null)
        {
            request = request ?? Request;

            if (request.Properties.ContainsKey("MS_HttpContext"))
            {
                return ((HttpContextWrapper)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
            }
            else if (request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name))
            {
                RemoteEndpointMessageProperty prop = (RemoteEndpointMessageProperty)this.Request.Properties[RemoteEndpointMessageProperty.Name];
                return prop.Address;
            }
            else if (HttpContext.Current != null)
            {
                return HttpContext.Current.Request.UserHostAddress;
            }
            else
            {
                return null;
            }
        }

        #endregion 获取客户端IP

        #region     检测此系统是否在SSO处授权
        /// <summary>
        /// 检测此系统是否在SSO处授权
        /// </summary>
        /// <param name="userInfo"></param>
        /// <returns></returns>
        private bool CheckAppPermision(UserInfo userInfo)
        {
            //检测此系统是否授权使用SSO
            bool result = false;
            if (!string.IsNullOrWhiteSpace(userInfo.AppKey) && !string.IsNullOrWhiteSpace(userInfo.AppSecret))
            {
                var ssoAuthtication = from p in db.Sso_Authtication
                                      where p.Sa_Enable == 0 &&
                                      p.Sa_App_Key == userInfo.AppKey &&
                                      p.Sa_App_Secret == userInfo.AppSecret
                                      select p;
                if (ssoAuthtication.Count() > 0)
                {
                    result = true;
                }

            }
            return result;
        }
        #endregion 检测此系统是否在SSO处授权

        #region     检测用户是否有登录某子系统的权限
        /// <summary>
        /// 检测用户是否有登录某子系统的权限
        /// </summary>
        /// <param name="userInfo"></param>
        /// <returns></returns>
        private bool CheckUserPermission(UserInfo userInfo)
        {
            bool hasPermission = false;
            //如果是登录时检测
            if (!string.IsNullOrWhiteSpace(userInfo.UserName))
            {
                if (!string.IsNullOrWhiteSpace(userInfo.AppKey))
                {
                    var ssoAuthtication = db.Sso_Authtication.Where(p => p.Sa_App_Key == userInfo.AppKey).ToList();
                    var sa_Id = ssoAuthtication.FirstOrDefault().Sa_Id;
                    var userName = userInfo.UserName;
                    var subSystem = from s in db.Sso_SubSystem
                                    where s.F_Authentication_Id == sa_Id &&
                                    s.F_UserName == userName
                                    select s;
                    if (subSystem.Count() > 0)
                    {
                        hasPermission = true;
                    }
                }
            }
            //如果是检测token
            else if (!string.IsNullOrWhiteSpace(userInfo.UserId))
            {
                if (!string.IsNullOrWhiteSpace(userInfo.AppKey))
                {
                    var ssoAuthtication = db.Sso_Authtication.Where(p => p.Sa_App_Key == userInfo.AppKey).ToList();
                    var sa_Id = ssoAuthtication.FirstOrDefault().Sa_Id;
                    var userId = userInfo.UserId;
                    var subSystem = from s in db.Sso_SubSystem
                                    where s.F_Authentication_Id == sa_Id &&
                                    s.F_User_Id == userId
                                    select s;
                    if (subSystem.Count() > 0)
                    {
                        hasPermission = true;
                    }
                }
            }

            return hasPermission;
        }

        #endregion 检测用户是否有登录某子系统的权限

        #region 检测用户是否在线

        /// <summary>
        /// 检测用户是否在线
        /// </summary>
        /// <param name="result"></param>
        /// <param name="userInfo"></param>
        /// <returns></returns>
        private bool CheckUserIsOnline(ref Result result, UserInfo userInfo)
        {
            bool isOnline = false;
            if (RedisCache.Exists(userInfo?.UserId))
            {
                var loginInfo = GetFromRedis<LoginInfo>(userInfo?.UserId);
                //如果用户ip和已登录的ip不同
                if (userInfo.Ip != loginInfo.IP)
                {
                    result.Code = 2;
                    result.Message = "已在其他电脑登录";
                }
                //如果检测到相同的ip已登录
                else
                {
                    OnlineInfo onlineInfo = new OnlineInfo();
                    onlineInfo.UserID = userInfo?.UserId;
                    onlineInfo.UserName = loginInfo.UserName;
                    onlineInfo.Token = loginInfo.Token;
                    onlineInfo.Expires = loginInfo.Expires;
                    result.Code = 0;
                    result.Message = "在线";
                    result.Data = onlineInfo;

                    isOnline = true;
                }

            }
            else
            {
                result.Code = 1;
                result.Message = "此用户未登录";
            }

            return isOnline;
        }


        #endregion 检测用户是否在线

        #region  检测用户名和密码是否正确
        /// <summary>
        /// 检测用户名和密码是否正确
        /// </summary>
        /// <param name="userInfo"></param>
        /// <returns>不正确返回int=0,正确返回用户的id，值大于0</returns>
        private string CheckUsername(UserInfo userInfo)
        {
            string userId = string.Empty;
            var ssoSubSystem = db.Sso_SubSystem.Where(p => p.F_UserName == userInfo.UserName && p.F_Password == userInfo.Password).ToList();
            if (ssoSubSystem.Count() > 0)
            {
                userId = ssoSubSystem.FirstOrDefault().F_User_Id;
            }
            return userId;
        }

        #endregion  检测用户名和密码是否正确

        #region 登录成功
        private void LoginSuccess(UserInfo userInfo, ref Result result)
        {
            //生成token
            //eg.d00eac8f5c9848169ef1865601833ce2
            string token = System.Guid.NewGuid().ToString("N");

            LoginInfo loginInfo = new LoginInfo();
            loginInfo.Token = token;
            loginInfo.UserName = userInfo.UserName;
            //eg."2017-03-09 11:22:10",超时时间取对应应用授权表里边的过期时间
            loginInfo.Expires = DateTime.Now.AddSeconds(1200).ToString("yyyy-MM-dd HH:mm:ss");
            loginInfo.AppKey = userInfo.AppKey;
            loginInfo.AppSecret = userInfo.AppSecret;
            loginInfo.IP = userInfo.Ip;

            //登录信息写入redis
            SaveToRedis(userInfo.UserId, loginInfo);

            OnlineInfo onlineInfo = new OnlineInfo();
            onlineInfo.Token = token;
            onlineInfo.UserID = userInfo.UserId;
            onlineInfo.UserName = userInfo.UserName;
            onlineInfo.Expires = loginInfo.Expires;

            result.Data = onlineInfo;
            result.Code = 0;
            result.Message = "登录成功";
        }
        #endregion 登录成功

        #endregion
    }
}
